﻿using System;

namespace ContextualStateless
{
    public partial class StateMachine< TState, TTrigger, TContext >
    {
        ///<summary>
        /// Delegate to context handler, invoked when triggers initiate transition.
        ///</summary>
        ///<param name="context">context</param>
        ///<param name="triggerName">trigger name</param>
        public delegate void ActionHandler( TContext context, TTrigger triggerName );

        ///<summary>
        /// Delegate to context handler, returning permission for a triggered state transition.
        /// Delegate returns result, indicating if state transition is possible (true) or not (false).
        /// This delegate acts as a second sequential guard for the state transition to allow more
        /// dynamic guard condition configuration.
        ///</summary>
        ///<param name="context">context</param>
        ///<param name="triggerName">trigger name</param>
        public delegate bool LogicalActionHandler( TContext context, TTrigger triggerName );

        /// <summary>
        /// Represents general (abstract) trigger with guard condition.
        /// </summary>
        internal protected abstract class AbstractTriggerRepresentation
        {
            #region Attributes

            /// <summary>
            /// Delegate to context handler.
            /// Invoked when the trigger is fired.
            /// </summary>
            public LogicalActionHandler ContextHandler { get; protected set; }

            /// <summary>
            /// Guard condition method.
            /// Trigger can be fired (CanFire() == true) and state transition is allowed if method returns true.
            /// </summary>
            readonly Func< TContext, bool > m_guardConditionMethod;

            /// <summary>
            /// Represented trigger.
            /// </summary>
            public TTrigger Trigger { get; protected set; }

            #endregion

            protected AbstractTriggerRepresentation( TTrigger trigger, Func<TContext, bool> guard, LogicalActionHandler contextHandler )
            {
                Trigger = trigger;
                m_guardConditionMethod = guard;
                ContextHandler = contextHandler;
            }

            // ------------------------------------------------------------------------------------------

            /// <summary>
            /// Returns indication if guard condition under the context is met (true) or not (false).
            /// </summary>
            /// <param name="context">context</param>
            /// <returns>true if guard condition is met and false otherwise</returns>
            public bool IsGuardConditionMet( TContext context )
            {
                return m_guardConditionMethod( context );
            }

            /// <summary>
            /// Checks if trigger can cause state transition from the state-source to the state-destination.
            /// </summary>
            /// <param name="source">source state for the state transition</param>
            /// <param name="args">additional transition parameters</param>
            /// <param name="context">context</param>
            /// <param name="destination">target state for the state transition</param>
            /// <returns>true if trigger causes state transition from the source to the destination state and false otherwise</returns>
            public abstract bool ResultsInTransitionFrom( TState source, object[] args, TContext context, out TState destination );
        }
    }
}
